Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Commit 9d6f9a19e03367be3000b0e09dc3396dfe6e8fc4


Parents : 43740d6
Author : Mark Qvist <mark@unsigned.io>
Date : 2025-11-26T20:21:49+01:00

Added FileRecorder primitive

Changes

2 files changed, 71 insertions(+), 2 deletions(-)


Diff

diff --git a/LXST/Primitives/Players.py b/LXST/Primitives/Players.py
index 08b3547..381b7da 100644
--- a/LXST/Primitives/Players.py
+++ b/LXST/Primitives/Players.py
@@ -1,5 +1,6 @@
import LXST
import time
+import threading
import os
from LXST.Sinks import LineSink
@@ -9,6 +10,7 @@ class FilePlayer():
def __init__(self, path=None, device=None, loop=False):
self._file_path = path
self._playback_device = None
+ self.__finished_callback = None
self.__loop = loop
self.__source = None
self.__sink = LineSink(self._playback_device)
@@ -26,6 +28,21 @@ class FilePlayer():
@property
def playing(self): return self.running
+ @property
+ def finished_callback(self): return self.__finished_callback
+
+ @finished_callback.setter
+ def finished_callback(self, callback):
+ if callback == None: self.__finished_callback = None
+ elif not callable(callback): raise TypeError("Provided callback is not callable")
+ else: self.__finished_callback = callback
+
+ def __callback_job(self):
+ if self.__finished_callback:
+ time.sleep(0.2)
+ while self.running: time.sleep(0.1)
+ self.__finished_callback(self)
+
def set_source(self, path=None):
if not path: return
else:
@@ -40,12 +57,14 @@ class FilePlayer():
if self.__source: self.__source.loop = self.__loop
def start(self):
- if self.__source:
+ if not self.running and self.__source:
self.__input_pipeline.start()
self.__output_pipeline.start()
+ if self.__finished_callback:
+ threading.Thread(target=self.__callback_job, daemon=True).start()
def stop(self):
- if self.__source:
+ if self.running and self.__source:
self.__input_pipeline.stop()
self.__output_pipeline.stop()

diff --git a/LXST/Primitives/Recorders.py b/LXST/Primitives/Recorders.py
new file mode 100644
index 0000000..9809251
--- /dev/null
+++ b/LXST/Primitives/Recorders.py
@@ -0,0 +1,50 @@
+import RNS
+import LXST
+import time
+import os
+from LXST.Sources import LineSource
+from LXST.Sinks import OpusFileSink
+
+class FileRecorder():
+ def __init__(self, path=None, device=None, profile=LXST.Codecs.Opus.PROFILE_AUDIO_MAX):
+ self._file_path = path
+ self._record_device = device
+ self.__profile = profile
+ self.__source = None
+ self.__sink = OpusFileSink(path=self._file_path)
+ self.__raw = LXST.Codecs.Raw()
+ self.__loopback = LXST.Sources.Loopback()
+ self.__output_pipeline = LXST.Pipeline(source=self.__loopback, codec=self.__raw, sink=self.__sink)
+ self.__input_pipeline = None
+ self.set_source(device)
+
+ @property
+ def running(self):
+ if not self.__source: return False
+ else: return self.__source.should_run
+
+ @property
+ def recording(self): return self.running
+
+ def set_source(self, device=None):
+ self._record_device = device
+ self.__source = LineSource(preferred_device=self._record_device, target_frame_ms=20, codec=self.__raw, sink=self.__loopback)
+ self.__input_pipeline = LXST.Pipeline(source=self.__source, codec=self.__raw, sink=self.__loopback)
+
+ def set_output_path(self, path):
+ self._file_path = path
+ self.__sink.__output_path = path
+
+ def start(self):
+ if self.__source:
+ self.__input_pipeline.start()
+ self.__output_pipeline.start()
+
+ def stop(self):
+ if self.__source:
+ self.__input_pipeline.stop()
+ self.__output_pipeline.stop()
+ self.__sink.stop()
+
+ def record(self):
+ self.start()
\ No newline at end of file


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────